#include "kernel.h"
extern "C"{
void kernelone(
		IN_TYPE offset1[OFFSET_LEN],IN_TYPE adj1[ADJ_LEN],
		IN_TYPE offset2[OFFSET_LEN],IN_TYPE adj2[ADJ_LEN],
		IN_TYPE cand1[CAN_LEN],CAN_TYPE cand2[CAN2_LEN],CAN_TYPE findex[INDEX_LEN],CAN_TYPE cindex[CINDEX_LEN],
		IN_TYPE size1,IN_TYPE size2,IN_TYPE index_size,IN_TYPE cindex_size,
		IN_TYPE pid1,CAN_TYPE type1,
		IN_TYPE out_buf[OUT_LEN]
		)
{
#pragma HLS INTERFACE m_axi port=cand1 offset=slave bundle=gmem0
#pragma HLS INTERFACE m_axi port=cand2 offset=slave bundle=gmem1
#pragma HLS INTERFACE m_axi port=out_buf offset=slave bundle=gmem2

#pragma HLS INTERFACE m_axi port=offset1 offset=slave bundle=gmem3
#pragma HLS INTERFACE m_axi port=adj1 offset=slave bundle=gmem4
#pragma HLS INTERFACE m_axi port=offset2 offset=slave bundle=gmem5
#pragma HLS INTERFACE m_axi port=adj2 offset=slave bundle=gmem6

#pragma HLS INTERFACE m_axi port=findex offset=slave bundle=gmem11
#pragma HLS INTERFACE m_axi port=cindex offset=slave bundle=gmem12

#pragma HLS INTERFACE s_axilite port=offset1 bundle=control
#pragma HLS INTERFACE s_axilite port=adj1 bundle=control
#pragma HLS INTERFACE s_axilite port=offset2 bundle=control
#pragma HLS INTERFACE s_axilite port=adj2 bundle=control

#pragma HLS INTERFACE s_axilite port=cand1 bundle=control
#pragma HLS INTERFACE s_axilite port=cand2 bundle=control
#pragma HLS INTERFACE s_axilite port=out_buf bundle=control
#pragma HLS INTERFACE s_axilite port=findex bundle=control
#pragma HLS INTERFACE s_axilite port=cindex bundle=control
#pragma HLS INTERFACE s_axilite port=size1 bundle=control
#pragma HLS INTERFACE s_axilite port=size2 bundle=control
#pragma HLS INTERFACE s_axilite port=pid1 bundle=control
#pragma HLS INTERFACE s_axilite port=type1 bundle=control
#pragma HLS INTERFACE s_axilite port=index_size bundle=control
#pragma HLS INTERFACE s_axilite port=cindex_size bundle=control
#pragma HLS INTERFACE s_axilite port=return bundle=control

	IN_TYPE size_c1 = 0;
	IN_TYPE size_c2 = 0;
	IN_TYPE size_i = 0;
	IN_TYPE pre_adj_count = 0;
	IN_TYPE pre_head = END_FLAG,pre_value = END_FLAG;
	IN_TYPE pre_end = 0,pre_begin = 0,pre_i=0,pre_size=0;

	static IN_TYPE preid1;

	static IN_TYPE cand1_buffer[1024][16];
	static IN_TYPE cand1_count = 0;
	static IN_TYPE cand1_bf_count[1024];
#pragma HLS BIND_STORAGE variable=cand1_bf_count type=ram_2p

	static IN_TYPE pre_off_buffer[64];
	static IN_TYPE pre_adj_buffer[512];

	//static CAN_TYPE block_buffer[512];

	static CAN_TYPE cindex_buffer[848672];

	static CAN_TYPE index_buffer[212256];
#pragma HLS BIND_STORAGE variable=index_buffer type=ram_2p impl=uram
	static IN_TYPE cand2_bf_count = 0;
	static IN_TYPE out_count=0;
	static IN_TYPE cand2_count = 0;
	static IN_TYPE out_iter = 0;
	IN_TYPE i,j,tmp,begin,end,adj_size,iter,jj,kk,index,efcount,efoff,bi,blc_begin,ci,csize;
	int bid,off,bbid,boff,pre_bbid,cbid,coff;
	CAN_TYPE tmpblock,tmpblock2,tmpblock3,tmptype,tmpblock4,tmpblock5,tmpblock6,tmpblock7,tmpblock8,tmpblock9;

	size_c1 = 0;
	size_c2 = 0;
	pre_bbid = 0;
	preid1 = 13;
	cand1_count = 0;
	cand2_bf_count = 0;
	out_count=0;
	cand2_count=0;
	out_iter = 0;
	i=0;
	j=0;
	begin=0;
	end=0;
	adj_size=0;
	iter=0;
	jj=0;
	kk=0;
	index = 0;
	size_c1 = size1;
	size_c2 = size2;
	size_i = index_size;
	csize = cindex_size;
	preid1 = pid1;
	tmptype = type1;
	blc_begin = 0;


	INDEX_LOAD:for(i=0;i<size_i;i++){
		index_buffer[i] = findex[i];
	}
	CINDEX_LOAD:for(ci=0;ci<csize;ci++){
		cindex_buffer[ci] = cindex[ci];
	}





	for(;cand1_count<size_c1;){
		//cout<<"a new iteration"<<endl;
		INITIAL2:for(i=0;i<1024;i++){
			#pragma HLS UNROLL factor=2
			cand1_bf_count[i]=0;
		}
		int tc2=0;
		CAND1_LOAD_OUTTER:for(i=0;i<1024 && cand1_count<size1;i++){
			tmp = cand1[cand1_count];
			cand1_count++;
			cand1_buffer[i][0]=tmp;
			cand1_bf_count[i]++;
			if(preid1==3){
				if(pre_head==END_FLAG || tmp - pre_head > 62){
					pre_head = tmp;
					for(pre_i=0;pre_i<64;pre_i++){
						pre_off_buffer[pre_i] = offset1[tmp+pre_i];
					}
					pre_begin = pre_off_buffer[0];
					pre_end = pre_off_buffer[63];
					pre_size = pre_end - pre_begin;
					for(pre_i=0;pre_i<pre_size;pre_i++){
						pre_adj_buffer[pre_i] = adj1[pre_begin+pre_i];
					}
				}
				begin = pre_off_buffer[tmp - pre_head] - pre_begin;
				end = pre_off_buffer[tmp - pre_head + 1] - pre_begin;
				adj_size = end - begin;
				READ_ADJ1:for(iter=0;iter<adj_size;iter++){
					cand1_buffer[i][cand1_bf_count[i]] = pre_adj_buffer[iter+begin];
					cand1_bf_count[i]++;
				}
			}else{
				if(pre_head==END_FLAG || tmp - pre_head > 62){
					pre_head = tmp;
					for(pre_i = 0;pre_i < 64;pre_i++){
						pre_off_buffer[pre_i] = offset2[tmp+pre_i];
					}
					pre_begin = pre_off_buffer[0];
					pre_end = pre_off_buffer[63];
					pre_size = pre_end - pre_begin;
					for(pre_i = 0;pre_i < pre_size;pre_i++){
						pre_adj_buffer[pre_i] = adj2[pre_begin+pre_i];
					}
				}
				begin = pre_off_buffer[tmp - pre_head] - pre_begin;
				end = pre_off_buffer[tmp - pre_head + 1] - pre_begin;
				adj_size = end - begin;
				READ_ADJ2:for(iter=0;iter<adj_size;iter++){
					cand1_buffer[i][cand1_bf_count[i]] = pre_adj_buffer[iter+begin];
					cand1_bf_count[i]++;
				}
			}
		}

		SEARCH_OUTTER:for(i=0;i<1024;i++){
			SEARCH_INNER:for( jj = 1;jj < cand1_bf_count[i] ; jj++ ){
				bbid = cand1_buffer[i][jj] / 4096;
				cbid = cand1_buffer[i][jj] / 1024;
				boff = (cand1_buffer[i][jj] / 512) % 8;
				coff = cand1_buffer[i][jj] % 8;
				tmpblock4 = index_buffer[bbid];
				tmpblock7 = cindex_buffer[cbid];
				tmpblock5 = 1<<(7-boff);
				tmpblock8 = 1<<(7-coff);
				tmpblock6 = tmpblock4&tmpblock5;
				tmpblock9 = tmpblock7&tmpblock8;
				if(tmpblock6==tmpblock5&&tmpblock9==tmpblock8){
					/*
					if(bbid != pre_bbid){
						blc_begin = bbid * 512;
						for(bi=0;bi<512;bi++){
							block_buffer[bi] = cand2[blc_begin+bi];
						}
					}
					*/
					//pre_bbid = bbid;
					//bid = (cand1_buffer[i][jj] % 4096) / 8;
					bid = cand1_buffer[i][jj] / 8;
					off = cand1_buffer[i][jj] % 8;
					tmpblock = cand2[bid];
					tmpblock2 = 1<<(7-off);
					tmpblock3 = tmpblock&tmpblock2;
					if(tmpblock3 == tmpblock2){
						out_buf[out_count++] = cand1_buffer[i][0];
						out_buf[out_count++] = cand1_buffer[i][jj];
					}
				}
			}
		}
	}
	efcount = out_count % 64;
	efoff = 64 - efcount + 1;
	for(i=0;i<efoff;i++){
		out_buf[out_count] = END_FLAG;
		out_count++;
	}
}
}
